package org.opens.javaskill.zip;

import cn.hutool.core.util.StrUtil;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 功能:
 *
 * @author zym
 * @Date 2021/11/19 9:46
 */
public class ZipUtil {

    /**
     * 功能: 将sourceFilePath这个路径或者文件压缩到zipFilePath路径下
     * @param sourceFilePath    压缩源
     * @param zipFilePath       压缩目标位置
     */
    public static void zip(String sourceFilePath, String zipFilePath) {
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
            doZip("", sourceFilePath, zipOutputStream);
            zipOutputStream.finish();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 功能: 真实的压缩方法
     * @param parentFilePath    父级节点名称
     * @param filePath          压缩文件输出路径
     * @param zipOutputStream   压缩文件输出流
     */
    private static void doZip(String parentFilePath, String filePath, ZipOutputStream zipOutputStream) {
        File sourceFile = new File(filePath);
        if (!sourceFile.exists()) {
            return;
        }
        String zipEntryName = parentFilePath + "/" + sourceFile.getName();
        if (StrUtil.isEmpty(parentFilePath)) {
            zipEntryName = sourceFile.getName();
        }

        if (sourceFile.isDirectory()) {
            File[] childFiles = sourceFile.listFiles();
            if (childFiles == null) {
                return;
            }
            for (File childFile : childFiles) {
                doZip(zipEntryName, childFile.getAbsolutePath(), zipOutputStream);
            }
        } else {
            int len = -1;
            byte[] buffer = new byte[1024];
            try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(sourceFile))) {
                zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
                while((len = bufferedInputStream.read(buffer)) != -1) {
                    zipOutputStream.write(buffer, 0, len);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 功能: 将压缩文件zipFilePath解压到指定路径下
     * @param zipFilePath   压缩文件路径
     * @param destFilePath  解压路径
     */
    public static void unzip(String zipFilePath, String destFilePath) {
        File file = new File(zipFilePath);
        if (!file.exists()) {
            return;
        }
        Charset charset = StandardCharsets.UTF_8;
        // 兼容windows的gbk编码, 否则压缩包名包含中文会报错
        if (isWindows()) {
            charset = Charset.forName("GBK");
        }

        try(
                ZipFile zipFile = new ZipFile(file, charset);
                ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(file))
        ) {
            ZipEntry zipEntry = null;
            String[] zipFileNameSplitRes = zipFile.getName().split("\\\\");
            String zipFileName = zipFileNameSplitRes[zipFileNameSplitRes.length - 1];

            // 先创建同名目录
            File unzipDir = new File(destFilePath, zipFileName.split("\\.")[0]);
            if (!unzipDir.exists()) {
                unzipDir.mkdirs();
            }

            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                // 增加zipFileName.split("\\.")[0]是为了解压后生成压缩文件路径下
                File entryFile = new File(unzipDir.getAbsolutePath(), zipEntry.getName());
                // 如果当前节点是目录, 则只创建目录
                if (zipEntry.isDirectory()) {
                    entryFile.mkdir();
                } else {
                    // 如果当前节点是文件, 则进行复制内容
                    if (!entryFile.getParentFile().exists()) {
                        entryFile.getParentFile().mkdirs();
                    }
                    entryFile.createNewFile();
                    try (
                            InputStream inputStream = zipFile.getInputStream(zipEntry);
                            OutputStream outputStream = new FileOutputStream(entryFile)
                    ) {
                        int len = -1;
                        byte[] buffer = new byte[1024];
                        while ((len = inputStream.read(buffer)) != -1) {
                            outputStream.write(buffer, 0, len);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        }
        return false;
    }

    public static boolean isWindows() {
        return System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS");
    }

}
